#include "events.h"
#include "board.h"
#include "gui.h"
#include "ai.h"
#include "util.h"
#include "threads.h"
#include "editor.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

extern Board* plansza;
extern Gui gui;

static volatile int moveLock = FALSE;

/* odrysuj pole gry */
gboolean drawingarea_paint(GtkWidget *widget, GdkEventExpose* event, gpointer data) {

	return draw_board_on_drawing_area(widget, plansza);

}


void move_lock() {

	moveLock = TRUE;

}

void move_unlock() {

	moveLock = FALSE;

}

/* odrysowanie pola bieżącego zawodnika */
gboolean current_player_draw(GtkWidget* widget, GdkEventExpose* event, gpointer data) {

	symbol currentMove;
	int width, height;

	GdkColor circleColor;
	GdkColor crossColor;
	GtkAllocation alloc;
	cairo_t* cr;

	double PI;

	PI = atan(1.0)*4.0;

	if(plansza == NULL)
		return FALSE;

	cr = gdk_cairo_create(widget->window);

	/* czerwone kółko */
	gdk_color_parse("#FF0000", &circleColor);

	/* niebieski krzyżyk */
	gdk_color_parse("#0000FF", &crossColor);
	
	currentMove = board_get_current_player_symbol (plansza);

	gtk_widget_get_allocation(widget, &alloc);

	width = alloc.width;
	height = alloc.height;
	
	if(currentMove == CIRCLE) {

		gdk_cairo_set_source_color(cr, &circleColor);

		cairo_arc (cr, width/2.0, height/2.0,
		     width/4.0, 0.0, 2.0*PI);

		cairo_set_line_width (cr, 5.0);
		cairo_stroke(cr);
		
	}
	else {

		cairo_set_line_width (cr, 5.0);
		gdk_cairo_set_source_color(cr, &crossColor);

		cairo_new_path(cr);

		cairo_move_to (cr, 0.25*width, 0.25*height);
		cairo_line_to (cr, 0.75*width, 0.75*height);

		cairo_stroke(cr);

		cairo_new_path(cr);

		cairo_move_to(cr, 0.75*width, 0.25*height);
		cairo_line_to(cr, 0.25*width, 0.75*height);
			
		cairo_stroke(cr);

	}

	return FALSE;

}

/* kliknięcie na pole gry */
gboolean game_area_clicked(GtkWidget *widget, GdkEvent *event, gpointer user_data) {

	Vector windowSize;
	Vector clickedCoord;
	int rozmiarPlanszy;
	GtkAllocation alloc;
	GdkEventButton* ev;

	/* Założona blokada... */
	if(moveLock)
		return FALSE;

	/* nie ma planszy, to nie ma co robić */
	if(plansza == NULL)
		return FALSE;

	/* sprawdzamy czy aktualny gracz jest człowiekiem,
	 * jeśli komputer oblicza ruch, to człowiek nie ma prawa
	 * się ruszyć */
	if(!board_is_current_move_human(plansza))
		return FALSE;

	/* jeśli gra się skończyła, nie można się ruszyć */
	if(board_is_game_finished (plansza))
		return FALSE;

	rozmiarPlanszy = board_size (plansza);

	ev = (GdkEventButton*)event;

	/* pobieramy współrzędne... */
	clickedCoord.x = ev->x;
	clickedCoord.y = ev->y;

	/* pobieramy rozmiar displaya */
	gtk_widget_get_allocation (widget, &alloc);
	windowSize.x = alloc.width;
	windowSize.y = alloc.height;

	/* pobieramy współrzędne klikniętego pola */
	clickedCoord = translate_point_to_coord(rozmiarPlanszy, clickedCoord, windowSize);

	/* nieprawidłowe koordynaty */
	if(clickedCoord.x == -1 || clickedCoord.y == -1)
	{
		return FALSE;
	}

	board_play(plansza, clickedCoord.x, clickedCoord.y);

	refresh_display();

	/* pokaż kto wygrał */
	if(board_is_game_finished (plansza)) {
		show_winner();
		return FALSE;
	}

	if(!board_is_current_move_human (plansza)) {
		
		/* wykonaj ruch komputera */
		thread_computer_make_move(plansza);
		
	}

	return FALSE;
	
}

void dialog_ok_clicked(GtkButton* button) {

	gtk_dialog_response (gui.gameSizeDialog, GTK_RESPONSE_OK);
	
}

void show_about_dialog(GtkToolButton* button) {

	char* authorsTable[] = { "Dominik Jastrzębski", NULL };

	gtk_show_about_dialog(gui.main, "program-name", "omringa", "version",
	                      "0.2", "comments", "Program zaliczeniowy na IPP",
	                      "authors", authorsTable, NULL);
	
}

/* nowa gra */
void new_game_clicked(GtkToolButton* button) {

	int val, val2;
	int firstComp, secondComp, crossComp, circleComp;
	G_CONST_RETURN char* entry1;
	G_CONST_RETURN char* entry2;
	float bid1, bid2, circlePts, crossPts;
	char buffer1[50];
	char buffer2[50];
	char buffer3[100];
	int result;
	GtkMessageDialog* msgDialog;

	memset(buffer1, 0, 50);
	memset(buffer2, 0, 50);

	result = gtk_dialog_run(gui.gameSizeDialog);

	gtk_widget_hide (GTK_WIDGET(gui.gameSizeDialog));

	if(result != GTK_RESPONSE_OK)
		return;

	/* rozmiar planszy */
	val = (int)gtk_spin_button_get_value (gui.dialogSpinButton);

	/* kara za grupę */
	val2 = (int)gtk_spin_button_get_value (gui.dialogSpinButton2);

	/* gracze-ludzie i gracze-komputery */
	if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.humanHuman))) {
		
		/* człowiek - człowiek */
		firstComp = FALSE;
		secondComp = FALSE;
		
		/* ustawiamy widoczność zawartości pól na FALSE, ale udostępniamy obydwa pola */
		gtk_entry_set_text(gui.firstPlayerBid, "");
		gtk_entry_set_text(gui.secondPlayerBid, "");
		gtk_widget_set_sensitive (GTK_WIDGET(gui.firstPlayerBid), TRUE);
		gtk_widget_set_sensitive (GTK_WIDGET(gui.secondPlayerBid), TRUE);
		gtk_entry_set_visibility (gui.firstPlayerBid, FALSE);
		gtk_entry_set_visibility (gui.secondPlayerBid, FALSE);
		
	}
	else if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.humanComputer))) {
		
		/* człowiek - komputer */
		firstComp = FALSE;
		secondComp = TRUE;

		/* ustawiamy widoczność pola 1 na TRUE, 2 na FALSE, ale blokujemy pole 2 */

		sprintf(buffer1, "%d", ai_make_bid(val, val2));		
		
		gtk_entry_set_text(gui.firstPlayerBid, "");
		gtk_entry_set_text(gui.secondPlayerBid, "");
		gtk_widget_set_sensitive (GTK_WIDGET(gui.firstPlayerBid), TRUE);
		gtk_widget_set_sensitive (GTK_WIDGET(gui.secondPlayerBid), FALSE);
		gtk_entry_set_visibility (gui.firstPlayerBid, TRUE);
		gtk_entry_set_visibility (gui.secondPlayerBid, FALSE);
		
	}
	else {
		
		/* komputer - komputer */
		firstComp = TRUE;
		secondComp = TRUE;

		/* ustawiamy widoczność zawartości pól na TRUE, ale blokujemy
		 * obydwa pola i od razu licytujemy za komputer */
		gtk_widget_set_sensitive (GTK_WIDGET(gui.firstPlayerBid), FALSE);
		gtk_widget_set_sensitive (GTK_WIDGET(gui.secondPlayerBid), FALSE);
		gtk_entry_set_visibility (gui.firstPlayerBid, TRUE);
		gtk_entry_set_visibility (gui.secondPlayerBid, TRUE);

		/* komputery losują losowo liczby z zakresu 1..2*KARA_ZA_GRUPĘ */

		sprintf(buffer1, "%d", ai_make_bid(val, val2));
		sprintf(buffer2, "%d", ai_make_bid(val, val2));

		gtk_entry_set_text(gui.firstPlayerBid, buffer1);
		gtk_entry_set_text(gui.secondPlayerBid, buffer2);
		
	}

	/* rozpoczynamy licytację */
	
	result = gtk_dialog_run (gui.biddingDialog);

	if(result != GTK_RESPONSE_OK) {
		gtk_widget_hide(GTK_WIDGET(gui.biddingDialog));
		return;
	}
	
	gtk_widget_hide(GTK_WIDGET(gui.biddingDialog));		

	/* pobieramy wartości z licytacji */
	entry1 = gtk_entry_get_text (gui.firstPlayerBid);
	entry2 = gtk_entry_get_text (gui.secondPlayerBid);

	sscanf(entry1, "%f", &bid1);
	sscanf(entry2, "%f", &bid2);

	/* weź obstawienie komputera */
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui.humanComputer))) 
		bid2 = ai_make_bid(val, val2);

	/* dodaj połówki */
	bid1 += 0.5;
	bid2 += 0.5;

	/* zabij wątki działające na planszy */
	thread_interrupt();
	
	if(plansza != NULL)
		board_cleanup(plansza);	

	/* Pierwszy gracz zaczyna kółkiem, drugi dostaje punkty */
	if(bid1 > bid2) {

		circlePts = 0.0;
		crossPts = bid2;
		circleComp = firstComp;
		crossComp = secondComp;

	}
	/* Drugi gracz zaczyna kółkiem, pierwszy dostaje punkty */
	else if(bid1 < bid2) {

		circlePts = 0.0;
		crossPts = bid1;
		circleComp = secondComp;
		crossComp = firstComp;

	}
	/* Losujemy kto zaczyna */
	else {

		/* zaczyna pierwszy */
		if(rand() % 2 == 0) {

			circlePts = 0.0;
			crossPts = bid2;
			circleComp = firstComp;
			crossComp = secondComp;
			
		}
		/* zaczyna drugi */
		else {

			circlePts = 0.0;
			crossPts = bid1;
			circleComp = firstComp;
			crossComp = secondComp;

		}

	}

	/* Inicjalizacja planszy */
	board_init(&plansza, val, val2, circlePts, crossPts, circleComp, crossComp);	

	refresh_display();	

	/* W grze człowiek-człowiek i człowiek-komputer wyświetl wynik licytacji */
	if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.humanHuman))) {

		sprintf(buffer3, "gracz 1 zalicytował: %.1f\ngracz 2 zalicytował: %.1f\n\n",
		        bid1, bid2);

		if(crossPts == bid1)
			strcat(buffer3, "(kółko): gracz 1\n(krzyżyk): gracz 2");
		else
			strcat(buffer3, "(kółko): gracz 2\n(krzyżyk): gracz 1");
		
		msgDialog = (GtkMessageDialog*)gtk_message_dialog_new(gui.main, GTK_DIALOG_MODAL,
		                                   GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
		                                   buffer3);

		gtk_dialog_run(GTK_DIALOG(msgDialog));

		gtk_widget_destroy(GTK_WIDGET(msgDialog));

		
		
	}
	else if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.humanComputer))) {

		
		sprintf(buffer3, "gracz zalicytował: %.1f\nkomputer zalicytował: %.1f\n\n",
		        			bid1, bid2);

		if(circleComp)
			strcat(buffer3, "(kółko): komputer\n(krzyżyk): gracz");
		else
			strcat(buffer3, "(kółko): gracz\n(krzyżyk): komputer");
		
		msgDialog = (GtkMessageDialog*) gtk_message_dialog_new(gui.main, GTK_DIALOG_MODAL,
		                                   GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
		                                   buffer3);

		gtk_dialog_run(GTK_DIALOG(msgDialog));

		gtk_widget_destroy(GTK_WIDGET(msgDialog));
		

	}

	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui.computerComputer))) {

		thread_computer_vs_computer(plansza);
		
	}
	else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui.humanComputer))) {

		/* jeśli pierwszy rusza się komputer, niech się rusza */
		/* (tylko gra człowiek - człowiek) */
		if(!board_is_current_move_human(plansza))
			thread_computer_make_move(plansza);

	}

	/* jeśli się udało, odblokowujemy zapis do pliku */
	gtk_widget_set_sensitive (GTK_WIDGET(gui.saveButton), TRUE);

}

/* otwórz zapisaną grę */
void open_clicked(GtkToolButton* button) {

	symbol s;
	
	int result = read_from_file(&plansza, GTK_WIDGET(gui.main));

	/* jeśli się udało, odblokowujemy zapis do pliku */
	if(result == 0) {
		
		gtk_widget_set_sensitive (GTK_WIDGET(gui.saveButton), TRUE);

		/* inicjalizacja */
		gtk_spin_button_set_value(gui.dialogSpinButton, board_size(plansza));
		gtk_spin_button_set_value(gui.dialogSpinButton2, board_get_penalty(plansza));

		gtk_widget_set_sensitive (GTK_WIDGET(gui.dialogSpinButton), FALSE);
		gtk_widget_set_sensitive (GTK_WIDGET(gui.dialogSpinButton2), FALSE);

		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gui.humanHuman), TRUE);
		
		/* odpalenie dialogu */
		gtk_dialog_run(GTK_DIALOG(gui.gameSizeDialog));

		/* sprzątanie */
		gtk_widget_hide(GTK_WIDGET(gui.gameSizeDialog));
		gtk_widget_set_sensitive (GTK_WIDGET(gui.dialogSpinButton), TRUE);
		gtk_widget_set_sensitive (GTK_WIDGET(gui.dialogSpinButton2), TRUE);

		/* ustawienie człowiek <-> komputer */
		s = board_get_current_player_symbol(plansza);

		if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.humanHuman))) {

			board_set_circle_computer(plansza, FALSE);
			board_set_cross_computer(plansza, FALSE);
			
		}
		else if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(gui.humanComputer))) {

			if(s == CIRCLE) {
				board_set_circle_computer(plansza, FALSE);
				board_set_cross_computer(plansza, TRUE);
			}
			else {
				board_set_circle_computer(plansza, TRUE);
				board_set_cross_computer(plansza, FALSE);
			}

		}
		else {
			board_set_circle_computer(plansza, TRUE);
			board_set_cross_computer(plansza, TRUE);
			thread_computer_vs_computer(plansza);
		}
		
	}

	refresh_display();

}

/* zapisz grę */
void save_clicked(GtkToolButton* button) {

	save_to_file(plansza, GTK_WIDGET(gui.main));

}

/* edytor plansz */
void editor_clicked(GtkToolButton* button) {

	editor_clear_board();
	
	gtk_dialog_run(gui.editor);
	gtk_widget_hide(GTK_WIDGET(gui.editor));

}

/* guzik "pas" */
void pass_clicked(GtkToolButton* button) {

	/* Założona blokada... */
	if(moveLock)
		return;

	if(plansza == NULL)
		return;

	/* nie wolno zagrywać po końcu gry */
	if(board_is_game_finished (plansza))
		return;

	/* nie wolno zagrywać podczas ruchu komputera */
	if(!board_is_current_move_human(plansza))
		return;

	board_pass(plansza);

	refresh_display();

	/* pokaż kto wygrał (pas może kończyć grę) */
	if(board_is_game_finished (plansza)) {
		show_winner();
		return;
	}

	if(!board_is_current_move_human (plansza)) {
		
		/* wykonaj ruch komputera */
		thread_computer_make_move(plansza);

	}
	
}

/* cofnięcie ruchu */
void undo_clicked(GtkToolButton* button) {

	/* Założona blokada... */
	if(moveLock)
		return;

	if(plansza == NULL)
		return;

	/* undo tylko na koniec gry lub w swoim ruchu */
	if(!board_is_game_finished(plansza)) {
		if(!board_is_current_move_human(plansza))
			return;
	}
	/* nie pozwalamy na undo przy komputer vs. komputer */
	else {
		if(board_is_computer_vs_computer(plansza))
			return;
	}
	
	board_undo(plansza);

	/* jeżeli zachodzi potrzeba, undo ruchu komputera */
	if(!board_is_current_move_human(plansza))
		board_undo(plansza);

	refresh_display();

}

/* podpowiedź */
void hint_clicked(GtkToolButton* button) {

	/* Założona blokada... */
	if(moveLock)
		return;

	/* pusta plansza */
	if(plansza == NULL)
		return;

	/* hint tylko w swoim ruchu */
	if(!board_is_current_move_human(plansza))
		return;

	if(board_is_game_finished(plansza))
		return;

	thread_hint(plansza);

}

/* spodziewany wynik gry */
void wizard_clicked(GtkToolButton* button) {

	/* Założona blokada... */
	if(moveLock)
		return;

	/* pusta plansza */
	if(plansza == NULL)
		return;

	/* wizard tylko w swoim ruchu */
	if(!board_is_current_move_human(plansza))
		return;

	if(board_is_game_finished(plansza))
		return;

	thread_predict(plansza);
	
}